
function statusSet(%status, %blid, %value) { $Pref::Server::Status_[%status, %blid] = %value; }
function statusGet(%status, %blid) { return $Pref::Server::Status_[%status, %blid]; }
function statusGetClient(%status, %client) { return %client.bl_id !$= "" ? statusGet(%status, %client.bl_id) : ""; }

function statusSetName(%status, %client, %name, %val, %toggle) {
	if(!%client.isAdmin) { messageClient(%client, 0, "You must be admin to use this command."); return; }
	if(%name+0 == 0) { // name
		if(%name $= "") %target = %client;
		else            %target = findClientByName(%name);
		if(!isObject(%target)) { messageClient(%client, 0, "No client with that name."); return; }
		%blid = %target.bl_id; if(%blid $= "") { messageClient(%client, 0, "Target has no bl_id"); return; }
		%targetName = %target.name @ " (" @ %blid @ ")";
	} else { // blid
		%target = "";
		%blid = %name;
		%targetName = "BL_ID " @ %blid;
	}
	if(%toggle && %val$="") {
		statusSet(%status, %blid, statusGet(%status, %blid) ? "" : "1");
	} else if(%toggle) {
		statusSet(%status, %blid, statusGet(%status, %blid)$=%val ? "" : %val);
	} else {
		statusSet(%status, %blid, %val);
	}
	%newstatus = statusGet(%status, %blid);
	messageClient(%client, 0, %targetName @ ": " @ %status @ " set to " @ (%newstatus$="" ? "None" : %newstatus));
	return %target;
}
function statusToggleName(%status, %client, %name) {
	return statusSetName(%status, %client, %name, "", 1);
}

$Status_List[ 0] = "Killer";
$Status_List[ 1] = "Harmless";
$Status_List[ 2] = "Vulnerable";
$Status_List[ 3] = "Invincible";
$Status_List[ 4] = "SpawnBan";
$Status_List[ 5] = "SuicideBan";
$Status_List[ 6] = "BuildBan";
$Status_List[ 7] = "ToolBan";
$Status_List[ 8] = "ForceDatablock";
$Status_List[ 9] = "Mute";
$Status_List[10] = "ForceRespawn";
$Status_List[11] = "Spiky";
$Status_List[12] = "Piercing";
$Status_List[13] = "LogicBan";
$Status_List[14] = "DupBan";
$Status_List[15] = "Gag";
$Status_ListCount = 16;

function serverCmdStatus(%client, %name) {
	if(!%client.isAdmin) { messageClient(%client, 0, "You must be admin to use this command."); return; }
	if(%name+0 == 0) { // name
		if(%name $= "") %target = %client;
		else            %target = findClientByName(%name);
		if(!isObject(%target)) { messageClient(%client, 0, "No client with that name."); return; }
		%blid = %target.bl_id; if(%blid $= "") { messageClient(%client, 0, "Target has no bl_id"); return; }
		%targetName = %target.name @ " (" @ %blid @ ")";
	} else {
		%target = "";
		%blid = %name;
		%targetName = "BL_ID " @ %blid;
	}
	
	%list = "";
	for(%i=0; %i<$Status_ListCount; %i++) {
		%statusname = $Status_List[%i];
		%status = statusGet(%statusname, %blid);
		if     (%status==1                   ) %list = %list @ %statusname @ ", ";
		else if(%status!$="" && %status!$="0") %list = %list @ %statusname @ "=" @ %status @ ", ";
	}
	if(%list $= "") %list = "None";
	else            %list = getSubStr(%list, 0, strLen(%list)-2);
	messageClient(%client, 0, %targetName @ " status: " @ %list);
}

function serverCmdDA(%client) { if(%client.isAdmin) { $canDamageAll = !$canDamageAll; messageClient(%client, 0, "canDamageAll = " @ $canDamageAll); } }
function serverCmdKiller      (%client, %name) {      statusToggleName("Killer"         , %client, %name); }
function serverCmdHarmless    (%client, %name) {      statusToggleName("Harmless"       , %client, %name); }
function serverCmdVulnerable  (%client, %name) {      statusToggleName("Vulnerable"     , %client, %name); }
function serverCmdInvincible  (%client, %name) { %c = statusToggleName("Invincible"     , %client, %name); if(isObject(%c) && isObject(%c.player)) { %c.player.invulnerable = statusGetClient("Invincible", %c); cancel(%c.player.reinvulnSched); } }
function serverCmdSpawnBan    (%client, %name) { %c = statusToggleName("SpawnBan"       , %client, %name); if(isObject(%c)) %c.spawnPlayer(); }
function serverCmdSuicideBan  (%client, %name) {      statusToggleName("SuicideBan"     , %client, %name); }
function serverCmdBuildBan    (%client, %name) {      statusToggleName("BuildBan"       , %client, %name); }
function serverCmdToolBan     (%client, %name) { %c = statusToggleName("ToolBan"        , %client, %name); if(isObject(%c) && isObject(%c.player)) %c.player.unmountImage(0); }
function serverCmdMute        (%client, %name) {      statusToggleName("Mute"           , %client, %name); }
function serverCmdGag         (%client, %name) {      statusToggleName("Gag"            , %client, %name); }
function serverCmdForceRespawn(%client, %name) { %c = statusToggleName("ForceRespawn"   , %client, %name); if(isObject(%c) && !isObject(%c.player)) %c.instantRespawn(); }
function serverCmdSpiky       (%client, %name) {      statusToggleName("Spiky"          , %client, %name); }
function serverCmdPiercing    (%client, %name) {      statusToggleName("Piercing"       , %client, %name); }
function serverCmdLogicBan    (%client, %name) {      statusToggleName("LogicBan"       , %client, %name); }
function serverCmdDupBan      (%client, %name) {      statusToggleName("DupBan"         , %client, %name); }
function serverCmdNoJet       (%client, %name) { %c = statusSetName("ForceDatablock", %client, %name, "PlayerNoJet"      , 1); statusUpdateDatablock(%c); }
function serverCmdHorse       (%client, %name) { %c = statusSetName("ForceDatablock", %client, %name, "HorseArmor"       , 1); statusUpdateDatablock(%c); }

function spawnBanDeletePlayer(%client) {
	if(isObject(%client.player)) %client.player.delete();
}
function setInvulnerable(%player, %status) {
	%player.invulnerable = %status;
}
function statusUpdateDatablock(%client) {
	if(isObject(%client) && isObject(%player = %client.player)) {
		%client.player.setDatablock(%player.desiredDatablock!$="" ? %player.desiredDatablock : "PlayerStandardArmor");
	}
}
function gagMessage(%msg) {
	%newMsg = "";
	for(%i=0; %i<strLen(%msg); %i++) {
		%c = getSubStr(%msg, %i, 1);
		if(%c $= " ") %newMsg = %newMsg @ " ";
		else if(strPos(strUpr(%c), %c) == -1) %newMsg = %newMsg @ "m";
		else if(strPos(strLwr(%c), %c) == -1) %newMsg = %newMsg @ "M";
		else if(strPos("0123456789", %c) != -1) %newMsg = %newMsg @ "n";
		else %newMsg = %newMsg @ %c;
	}
	return %newMsg;
}

package Torment {
	function GameConnection::spawnPlayer(%client){
		if(statusGetClient("SpawnBan", %client)){
			schedule(33, 0, spawnBanDeletePlayer, %client);
		}
		return parent::spawnPlayer(%client);
	}
	
	function serverCmdSuicide(%client){
		if(statusGetClient("SuicideBan", %client)) return;
		if(%client.player.invulnerable) %client.player.invulnerable = 0;
		parent::serverCmdSuicide(%client);
	}
	function serverCmdPlantBrick(%client){
		if(statusGetClient("BuildBan", %client) || statusGetClient("ToolBan", %client)) return;
		if(isObject(%client.player) && isObject(%client.player.tempBrick) &&
			%client.player.tempBrick.getDatablock().isLogic && statusGetClient("LogicBan", %client)) return;
		parent::serverCmdPlantBrick(%client);
	}
	
	function serverCmdCreateMinigame(%client, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8){
		if(statusGetClient("SuicideBan", %client) || statusGetClient("SpawnBan", %client)) return;
		parent::serverCmdCreateMinigame(%client, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8);
	}
	function serverCmdJoinMinigame(%client, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8){
		if(statusGetClient("SuicideBan", %client) || statusGetClient("SpawnBan", %client)) return;
		parent::serverCmdJoinMinigame(%client, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8);
	}
	function serverCmdAcceptMinigameInvite(%client, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8){
		if(statusGetClient("SuicideBan", %client) || statusGetClient("SpawnBan", %client)) return;
		parent::serverCmdAcceptMinigameInvite(%client, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8);
	}
	function serverCmdClearCheckpoint(%client) {
		if(statusGetClient("SuicideBan", %client) || statusGetClient("SpawnBan", %client)) return;
		parent::serverCmdClearCheckpoint(%client);
	}
	
	function serverCmdMessageSent(%client, %msg){
		if(statusGetClient("Mute", %client)) return;
		if(statusGetClient("Gag", %client)) %msg = gagMessage(%msg);
		parent::serverCmdMessageSent(%client, %msg);
	}
	function serverCmdTeamMessageSent(%client, %msg){
		if(statusGetClient("Mute", %client)) return;
		parent::serverCmdTeamMessageSent(%client, %msg);
	}
	function serverCmdStartTalking(%client) {
		if(statusGetClient("Mute", %client)) return;
		parent::serverCmdStartTalking(%client);
	}
	
	function GameConnection::onDeath(%client, %sourceObject, %sourceClient, %damageType, %location) {
		parent::onDeath(%client, %sourceObject, %sourceClient, %damageType, %location);
		if(statusGetClient("ForceRespawn", %client)) {
			%client.schedule(0, instantRespawn);
		}
	}
	function GameConnection::createPlayer(%client, %spawnpoint) {
		parent::createPlayer(%client, %spawnpoint);
		%forcedb = statusGetClient("ForceDatablock", %client);
		if(%forcedb!$="") {
			%player = %client.player;
			if(isObject(%player)) {
				%player.setDatablock(%player.getDatablock());
			}
		}
		if(statusGetClient("Invincible", %client)) {
			%player = %client.player;
			if(isObject(%player)) {
				%player.invulnerable = 1;
			}
		}
	}
	function Player::setDatablock(%player, %datablock) {
		if(isObject(%player.client) && (%forcedb = statusGetClient("ForceDatablock", %player.client))!$="") {
			%player.desiredDatablock = %datablock;
			%datablock = %forcedb;
		}
		parent::setDatablock(%player, %datablock);
	}
	
	function minigameCanDamage(%attacker, %target) {
		if(%attacker.getClassName() $= "fxDtsBrick") {
			%mg1 = getMinigameFromObject(%attacker);
			if(!%mg1.brickDamage){ return 0; }
		}
		
		%attackerclient = %attacker.getClassName() $= "GameConnection" ? %attacker : %attacker.client;
		%targetclient   = %target  .getClassName() $= "GameConnection" ? %target   : %target  .client;
		
		if(statusGetClient("Piercing"  , %attackerclient) && isObject(%targetclient.player) && %targetclient.player.invulnerable) {
			%targetclient.player.invulnerable = 0;
			cancel(%targetclient.player.reinvulnSched);
			%targetclient.player.reinvulnSched = schedule(1, 0, setInvulnerable, %targetclient.player, 1);
		}
		
		if(statusGetClient("Invincible", %targetclient  ) && !statusGetClient("Piercing", %attackerclient)) { return 0; }
		if(statusGetClient("Harmless"  , %attackerclient) && %attackerclient != %targetclient) { return 0; }
		if($canDamageAll) { return 1; }
		if(statusGetClient("Killer"    , %attackerclient)) { return 1; }
		if(statusGetClient("Vulnerable", %targetclient  )) { return 1; }
		
		if(parent::minigameCanDamage(%attacker, %target) == 1) { return 1; }
		
		return 0;
	}
	
	function serverCmdUseTool(%client, %slot) {
		if(statusGetClient("ToolBan", %client)) return;
		parent::serverCmdUseTool(%client, %slot);
	}
	function serverCmdUseSprayCan(%client, %index) {
		if(statusGetClient("ToolBan", %client)) return;
		parent::serverCmdUseSprayCan(%client, %index);
	}
	function Player::mountImage(%player, %image, %slot) {
		if(isObject(%client = %player.client) && isObject(%image)) {
			if(statusGetClient("ToolBan", %client)) return;
			%name = %image.getName();
			if((getSubStr(%name, 0, 8) $= "ND_Image" || %name $= "fillcanImage") &&
				(statusGetClient("BuildBan", %client) || statusGetClient("DupBan", %client))) return;
			if(statusGetClient("BuildBan", %client) &&
				(%name $= "brickImage" || getSubStr(%name, strLen(%name)-13, strLen(%name)) $= "SprayCanImage" || %name $= "fillcanImage")) return;
		}
		parent::mountImage(%player, %image, %slot);
	}
	
	function Armor::onCollision(%data, %player, %col, %vec, %speed) {
		parent::onCollision(%data, %player, %col, %vec, %speed);
		if(%col.getType() & $TypeMasks::PlayerObjectType) {
			if(statusGetClient("Spiky", %player.client)) {
				%col.damage(%player, %player.getPosition(), 100, $DamageType::Fall);
			}
		}
	}
	
	function serverCmdRespawn(%client, %name) {
		if(!%client.isAdmin) { messageClient(%client, 0, "You must be admin to use this command."); return; }
		if(%name $= "") %target = %client; else %target = findClientByName(%name);
		if(!isObject(%target)) { messageClient(%client, 0, "No client named " @ %name @ " found."); return; }
		%target.instantRespawn();
		messageClient(%client, 0, "Respawned " @ %target.name);
	}
};
schedule(0, 0, activatePackage, Torment);
schedule(100, 0, resetAllOpCallFunc);
